/* -*- mode: c++ -*- */
/****************************************************************************
 *****                                                                  *****
 *****                   Classification: UNCLASSIFIED                   *****
 *****                    Classified By:                                *****
 *****                    Declassify On:                                *****
 *****                                                                  *****
 ****************************************************************************
 *
 *
 * Developed by: Naval Research Laboratory, Tactical Electronic Warfare Div.
 *               EW Modeling & Simulation, Code 5773
 *               4555 Overlook Ave.
 *               Washington, D.C. 20375-5339
 *
 * License for source code can be found at:
 * https://github.com/USNavalResearchLaboratory/simdissdk/blob/master/LICENSE.txt
 *
 * The U.S. Government retains all rights to use, duplicate, distribute,
 * disclose, or release this software.
 *
 */
#ifndef DATATYPES_H
#define DATATYPES_H

// File to wrap the simData.pb.h file generated by
// protoc with the appropriate resources

#include <limits>
#include "simCore/Common/Common.h"
#include "simCore/Calc/Vec3.h"

#undef ABSOLUTE
#undef RELATIVE

#ifdef _MSC_VER // [
#pragma warning(push)
// Disable C4244: "conversion from __int64 to int, possible loss of data"
// Disable C4251: "identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'"
// Disable C4267: "conversion from size_t to int, possible loss of data"
// Disable C4275: non-DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier'
// Disable C4996: "'std::_Copy_impl': Function call with parameters that may be unsafe"
#pragma warning(disable : 4244 4251 4267 4275 4996)
#endif // _MSC_VER ]

#include "simData.pb.h"


#ifdef _MSC_VER // [
#pragma warning(pop)
#endif // _MSC_VER ]

// Although proto buffers are flexible, they consume too much memory
// Below are memory efficient definitions for the POSIT classes

namespace simData
{
  /** Platform TSPI
   * (interface matches a Google protobuf message)
   */
  class SDKDATA_EXPORT PlatformUpdate
  {
  public:
    PlatformUpdate();
    // Do NOT make virtual, since it will consume memory space
    ~PlatformUpdate() {};

    /// copy over this with 'from'
    void CopyFrom(const PlatformUpdate& from);

    /// copy-constructor
    PlatformUpdate(const PlatformUpdate& from) { CopyFrom(from); }

    /// assignment operator
    inline PlatformUpdate& operator=(const PlatformUpdate& from) { CopyFrom(from);  return *this; }

    /**@name accessors -------------------------------------------------------
     *@{
     */
    inline bool has_time() const { return time_ != std::numeric_limits<double>::max(); }
    inline void clear_time() {time_ = std::numeric_limits<double>::max();}
    inline double time() const { return time_; }
    inline void set_time(double value) { time_ = value; }

    inline bool has_position() const { return has_x() && has_y() && has_z(); }
    inline void position(simCore::Vec3& vec) const { vec.setX(x_); vec.setY(y_); vec.setZ(z_); }
    inline void setPosition(const simCore::Vec3& vec) { x_ = vec.x(); y_ = vec.y(); z_ = vec.z(); }

    inline bool has_x() const { return x_ != std::numeric_limits<double>::max();}
    inline void clear_x() { x_ = std::numeric_limits<double>::max(); }
    inline double x() const { return x_; }
    inline void set_x(double value) { x_ = value; }

    inline bool has_y() const {return y_ != std::numeric_limits<double>::max();}
    inline void clear_y() { y_ = std::numeric_limits<double>::max(); }
    inline double y() const { return y_; }
    inline void set_y(double value) { y_ = value; }

    inline bool has_z() const {return z_ != std::numeric_limits<double>::max();}
    inline void clear_z() { z_ = std::numeric_limits<double>::max(); }
    inline double z() const {return z_;}
    inline void set_z(double value) { z_ = value; }

    inline bool has_orientation() const { return has_psi() && has_theta() && has_phi(); }
    inline void orientation(simCore::Vec3& vec) const { vec.setPsi(static_cast<double>(psi_)); vec.setTheta(static_cast<double>(theta_)); vec.setPhi(static_cast<double>(phi_)); }
    inline void setOrientation(const simCore::Vec3& vec) { psi_ = static_cast<float>(vec.psi()); theta_ = static_cast<float>(vec.theta()); phi_ = static_cast<float>(vec.phi()); }

    inline bool has_psi() const { return psi_ != std::numeric_limits<float>::max(); }
    inline void clear_psi() { psi_ = std::numeric_limits<float>::max(); }
    inline double psi() const {return psi_;}
    inline void set_psi(double value) { psi_ = static_cast<float>(value); }

    inline bool has_theta() const { return theta_ != std::numeric_limits<float>::max(); }
    inline void clear_theta() { theta_ = std::numeric_limits<float>::max(); }
    inline double theta() const {return theta_;}
    inline void set_theta(double value) { theta_ = static_cast<float>(value); }

    inline bool has_phi() const { return phi_ != std::numeric_limits<float>::max(); }
    inline void clear_phi() { phi_ = std::numeric_limits<float>::max(); }
    inline double phi() const { return phi_; }
    inline void set_phi(double value) { phi_ = static_cast<float>(value); }

    inline bool has_velocity() const { return has_vx() && has_vy() && has_vz(); }
    inline void velocity(simCore::Vec3& vec) const { vec.setV0(static_cast<double>(vx_)); vec.setV1(static_cast<double>(vy_)); vec.setV2(static_cast<double>(vz_)); }
    inline void setVelocity(const simCore::Vec3& vec) { vx_ = static_cast<float>(vec.x()); vy_ = static_cast<float>(vec.y()); vz_ = static_cast<float>(vec.z()); }

    inline bool has_vx() const { return vx_ != std::numeric_limits<float>::max(); }
    inline void clear_vx() { vx_ = std::numeric_limits<float>::max(); }
    inline double vx() const { return vx_; }
    inline void set_vx(double value) { vx_ = static_cast<float>(value); }

    inline bool has_vy() const { return vy_ != std::numeric_limits<float>::max(); }
    inline void clear_vy() { vy_ = std::numeric_limits<float>::max(); }
    inline double vy() const { return vy_; }
    inline void set_vy(double value) { vy_ = static_cast<float>(value); }

    inline bool has_vz() const { return vz_ != std::numeric_limits<float>::max(); }
    inline void clear_vz() { vz_ = std::numeric_limits<float>::max(); }
    inline double vz() const { return vz_; }
    inline void set_vz(double value) { vz_ = static_cast<float>(value); }
    ///@}

  private:
    /// Seconds since the reference year
    double time_;

    /// Position is in ECEF coordinates, meters
    double x_;
    double y_;
    double z_;

    /// The following are declared as floats to save space
    /// Alignment of a body in 3D space, angles in radians; earth centric
    float psi_;
    float theta_;
    float phi_;

    /// 3D vector for velocity, m/s
    float vx_;
    float vy_;
    float vz_;
  };

  /// compare for inequality (required for protobuf utils)
  SDKDATA_EXPORT bool operator!=(const Position &left, const Position &right);

  /// compare for equality (required for protobuf utils)
  SDKDATA_EXPORT bool operator==(const Position &left, const Position &right);
}

#endif

